﻿using Castle.MicroKernel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WJP.Dependency
{
    /// <summary>
    /// <see cref="IIocResolver"/>接口的扩展方法
    /// </summary>
    public static class IocResolverExtensions
    {
        /// <summary>
        /// 获取一个<see cref="IDisposableDependencyObjectWrapper{T}"/>对象，该对象将已解析的对象包装为IDisposable对象
        /// </summary>
        /// <typeparam name="T">要获取的对象</typeparam>
        /// <param name="iocResolver">IIocResolver对象</param>
        /// <returns>被<see cref="IDisposableDependencyObjectWrapper{T}"/>对象包装的实例</returns>
        public static IDisposableDependencyObjectWrapper<T> ResolveAsDisposable<T>(this IIocResolver iocResolver)
        {
            return new DisposableDependencyObjectWrapper<T>(iocResolver, iocResolver.Resolve<T>());
        }

        /// <summary>
        /// 获取一个<see cref="IDisposableDependencyObjectWrapper{T}"/>对象，该对象将已解析的对象包装为IDisposable对象
        /// </summary>
        /// <param name="iocResolver">IIocResolver对象</param>
        /// <param name="type">要获取的对象</param>
        /// <returns>被<see cref="IDisposableDependencyObjectWrapper{T}"/>对象包装的实例</returns>
        public static IDisposableDependencyObjectWrapper ResolveAsDisposable(this IIocResolver iocResolver, Type type)
        {
            return new DisposableDependencyObjectWrapper(iocResolver, iocResolver.Resolve(type));
        }

        /// <summary>
        /// 获取一个<see cref="IDisposableDependencyObjectWrapper{T}"/>对象，该对象将已解析的对象包装为IDisposable对象
        /// </summary>
        /// <param name="iocResolver">IIocResolver对象</param>
        /// <param name="arguments"></param>
        /// <returns>被<see cref="IDisposableDependencyObjectWrapper{T}"/>对象包装的实例</returns>
        public static IDisposableDependencyObjectWrapper<T> ResolveAsDisposable<T>(this IIocResolver iocResolver, Arguments arguments)
        {
            return new DisposableDependencyObjectWrapper<T>(iocResolver, iocResolver.Resolve<T>(arguments));
        }

        /// <summary>
        /// 获取一个<see cref="IDisposableDependencyObjectWrapper{T}"/>对象，该对象将已解析的对象包装为IDisposable对象
        /// </summary>
        /// <typeparam name="T">要获取的对象</typeparam>
        /// <param name="iocResolver">IIocResolver对象</param>
        /// <param name="type">要解析的对象类型，这个类型必须能被转换为<typeparamref name="T"/></param>
        /// <returns></returns>
        public static IDisposableDependencyObjectWrapper<T> ResolveAsDisposable<T>(this IIocResolver iocResolver, Type type)
        {
            return new DisposableDependencyObjectWrapper<T>(iocResolver, (T)iocResolver.Resolve(type));
        }


        /// <summary>
        /// 创建一个<see cref="ScopedIocResolver"/>对象
        /// </summary>
        /// <param name="iocResolver"></param>
        /// <returns></returns>
        public static IScopedIocResolver CreateScope(this IIocResolver iocResolver)
        {
            return new ScopedIocResolver(iocResolver);
        }

        /// <summary>
        /// 此方法可用于自动解析和释放对象
        /// </summary>
        /// <typeparam name="T">要使用的对象的类型</typeparam>
        /// <param name="iocResolver">IIocResolver对象</param>
        /// <param name="action">可以使用已解析对象的操作</param>
        public static void Using<T>(this IIocResolver iocResolver, Action<T> action)
        {
            using (var wrapper = iocResolver.ResolveAsDisposable<T>())
            {
                action(wrapper.Object);
            }
        }

        /// <summary>
        /// 此方法可用于自动解析和释放对象
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="iocResolver"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static TReturn Using<TService, TReturn>(this IIocResolver iocResolver, Func<TService, TReturn> func)
        {
            using (var obj = iocResolver.ResolveAsDisposable<TService>())
            {
                return func(obj.Object);
            }
        }

        /// <summary>
        /// 此方法启动一个范围来自动解析和释放所有对象
        /// </summary>
        /// <param name="iocResolver"></param>
        /// <param name="action"></param>
        public static void UsingScope(this IIocResolver iocResolver, Action<IScopedIocResolver> action)
        {
            using (var scope = iocResolver.CreateScope())
            {
                action(scope);
            }
        }
    }
}
